// src/lib.rs
#[derive(Debug, PartialEq, Eq)]
pub struct RequestLine {
    pub method: String,
    pub path: String,
    pub version: String,
}

pub fn parse_request_line(line: &str) -> RequestLine {
    let mut parts = line.split_whitespace();
    let method = parts.next().unwrap_or_default().to_string();
    let path = parts.next().unwrap_or_default().to_string();
    let version = parts.next().unwrap_or_default().to_string();

    RequestLine {
        method,
        path,
        version,
    }
}

pub struct Response {
    pub status_line: String,
    pub headers: Vec<(String, String)>,
    pub body: String,
}

pub fn build_response(response: Response) -> String {
    let mut http = response.status_line;
    http.push_str("\r\n");

    for (key, value) in response.headers {
        http.push_str(&format!("{key}: {value}\r\n"));
    }

    http.push_str("\r\n");
    http.push_str(&response.body);

    http
}

pub struct RouteMatch {
    pub status_line: &'static str,
    pub filename: &'static str,
}

pub fn route_request(request: &RequestLine) -> RouteMatch {
    match request {
        RequestLine {
            method,
            path,
            ..
        } if method == "GET" && path == "/" => RouteMatch {
            status_line: "HTTP/1.1 200 OK",
            filename: "hello.html",
        },
        _ => RouteMatch {
            status_line: "HTTP/1.1 404 NOT FOUND",
            filename: "404.html",
        },
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_request_line_extracts_method_path_version() {
        let line = "GET /hello HTTP/1.1";
        let parsed = parse_request_line(line);

        assert_eq!(
            parsed,
            RequestLine {
                method: "GET".into(),
                path: "/hello".into(),
                version: "HTTP/1.1".into()
            }
        );
    }

    #[test]
    fn parse_request_line_handles_missing_fields() {
        let line = "GET /";
        let parsed = parse_request_line(line);

        assert_eq!(
            parsed,
            RequestLine {
                method: "GET".into(),
                path: "/".into(),
                version: "".into()
            }
        );
    }

    #[test]
    fn build_response_serializes_struct_to_http_string() {
        let response = Response {
            status_line: "HTTP/1.1 200 OK".into(),
            headers: vec![("Content-Length".into(), "5".into())],
            body: "Hello".into(),
        };

        assert_eq!(
            build_response(response),
            "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nHello"
        );
    }


    #[test]
    fn build_response_allows_empty_headers() {
        let response = Response {
            status_line: "HTTP/1.1 404 NOT FOUND".into(),
            headers: vec![],
            body: "Not Found".into(),
        };

        assert_eq!(
            build_response(response),
            "HTTP/1.1 404 NOT FOUND\r\n\r\nNot Found"
        );
    }

    #[test]
    fn route_request_returns_root_page() {
        let request = RequestLine {
            method: "GET".into(),
            path: "/".into(),
            version: "HTTP/1.1".into(),
        };

        let route = route_request(&request);

        assert_eq!(route.status_line, "HTTP/1.1 200 OK");
        assert_eq!(route.filename, "hello.html");
    }

    #[test]
    fn route_request_returns_404_for_unknown_path() {
        let request = RequestLine {
            method: "GET".into(),
            path: "/unknown".into(),
            version: "HTTP/1.1".into(),
        };

        let route = route_request(&request);

        assert_eq!(route.status_line, "HTTP/1.1 404 NOT FOUND");
        assert_eq!(route.filename, "404.html");
    }
}
